package com.example.chamberlainserver.Service.impl;

import com.example.chamberlainserver.Entry.DormTrippingRecord;
import com.example.chamberlainserver.Entry.Material;
import com.example.chamberlainserver.Entry.MaterialStockLog;
import com.example.chamberlainserver.Entry.User;
import com.example.chamberlainserver.Entry.UserActionLog;
import com.example.chamberlainserver.Entry.Role;
import com.example.chamberlainserver.Service.UserRoleService;
import com.example.chamberlainserver.mapper.UserActionLogMapper;
import com.example.chamberlainserver.Service.DashboardService;
import com.example.chamberlainserver.Service.UserLogService;
import com.example.chamberlainserver.Vo.Request.Dashboard.DashboardQuery;
import com.example.chamberlainserver.Vo.Response.Dashboard.DashboardDTO;
import com.example.chamberlainserver.mapper.DormTrippingRecordMapper;
import com.example.chamberlainserver.mapper.MaterialCategoryMapper;
import com.example.chamberlainserver.mapper.MaterialMapper;
import com.example.chamberlainserver.mapper.UserMapper;
import com.example.chamberlainserver.security.RoleConstants;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.AbstractMap.SimpleEntry;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 数据大屏服务实现类
 */
@Slf4j
@Service
public class DashboardServiceImpl implements DashboardService {

    @Autowired
    private UserMapper userMapper;
    
    @Autowired
    private MaterialMapper materialMapper;
    
    @Autowired
    private MaterialCategoryMapper categoryMapper;
    
    @Autowired
    private DormTrippingRecordMapper trippingRecordMapper;
    
    @Autowired
    private UserLogService userLogService;
    
    @Autowired
    private com.example.chamberlainserver.mapper.MaterialStockLogMapper materialStockLogMapper;
    
    @Autowired
    private com.example.chamberlainserver.mapper.UserActionLogMapper userActionLogMapper;
    
    @Autowired
    private UserRoleService userRoleService;
    
    @Override
    public DashboardDTO.SystemOverview getSystemOverview() {
        // 获取用户总数
        Integer userCount = userMapper.getAllUsers().size();
        
        // 获取物资总数
        Integer materialCount = materialMapper.getAllMaterials().size();
        
        // 获取物资分类总数
        Integer categoryCount = categoryMapper.getAllCategories().size();
        
        // 获取跳闸记录总数
        Integer trippingRecordCount = trippingRecordMapper.getAllRecords().size();
        
        // 获取库存不足物资数量
        Integer lowStockCount = materialMapper.getAllMaterials().stream()
                .filter(m -> m.getQuantity() < m.getMinQuantity())
                .collect(Collectors.toList()).size();
        
        // 获取待处理跳闸记录数量
        Integer pendingTrippingCount = trippingRecordMapper.getRecordsByHandleStatus(false).size();
        
        return DashboardDTO.SystemOverview.builder()
                .userCount(userCount)
                .materialCount(materialCount)
                .categoryCount(categoryCount)
                .trippingRecordCount(trippingRecordCount)
                .lowStockCount(lowStockCount)
                .pendingTrippingCount(pendingTrippingCount)
                .build();
    }
    
    @Override
    public DashboardDTO.MaterialOverview getMaterialOverview() {
        List<Material> materials = materialMapper.getAllMaterials();
        
        // 统计各状态物资数量
        int normal = 0;
        int lowStock = 0;
        int needReplenish = 0;
        int scrapped = 0;
        
        for (Material material : materials) {
            switch (material.getStatus()) {
                case "正常":
                    normal++;
                    break;
                case "不足":
                    lowStock++;
                    break;
                case "待补充":
                    needReplenish++;
                    break;
                case "已报废":
                    scrapped++;
                    break;
            }
        }
        
        return DashboardDTO.MaterialOverview.builder()
                .normal(normal)
                .lowStock(lowStock)
                .needReplenish(needReplenish)
                .scrapped(scrapped)
                .build();
    }
    
    @Override
    public DashboardDTO.UserActivity getUserActivity(String period) {
        // 获取当前时间
        LocalDateTime now = LocalDateTime.now();
        
        // 根据统计周期确定起始时间
        LocalDateTime startTime;
        switch (period) {
            case "day":
                startTime = LocalDateTime.of(now.toLocalDate(), LocalTime.MIN);
                break;
            case "week":
                startTime = LocalDateTime.of(now.toLocalDate().minusDays(7), LocalTime.MIN);
                break;
            case "month":
                startTime = LocalDateTime.of(now.toLocalDate().minusMonths(1), LocalTime.MIN);
                break;
            default:
                startTime = LocalDateTime.of(now.toLocalDate().minusYears(1), LocalTime.MIN);
                break;
        }
        
        // 从数据库获取活跃用户数据
        LocalDateTime endTime = now;
        
        // 统计日活跃用户数（今天有操作记录的不同用户数）
        LocalDateTime todayStart = LocalDateTime.of(now.toLocalDate(), LocalTime.MIN);
        int dailyActive = getDailyActiveUsers(todayStart, endTime);
        
        // 统计周活跃用户数（最近7天有操作记录的不同用户数）
        LocalDateTime weekStart = LocalDateTime.of(now.toLocalDate().minusDays(7), LocalTime.MIN);
        int weeklyActive = getActiveUsers(weekStart, endTime);
        
        // 统计月活跃用户数（最近30天有操作记录的不同用户数）
        LocalDateTime monthStart = LocalDateTime.of(now.toLocalDate().minusDays(30), LocalTime.MIN);
        int monthlyActive = getActiveUsers(monthStart, endTime);
        
        // 从数据库获取用户角色分布
        List<DashboardDTO.UserActivity.RoleDistribution> roleDistribution = getUserRoleDistribution();
        
        return DashboardDTO.UserActivity.builder()
                .dailyActive(dailyActive)
                .weeklyActive(weeklyActive)
                .monthlyActive(monthlyActive)
                .userRoleDistribution(roleDistribution)
                .build();
    }
    
    /**
     * 获取指定时间段内的活跃用户数
     */
    private int getDailyActiveUsers(LocalDateTime startTime, LocalDateTime endTime) {
        // 使用原生SQL查询指定时间段内不同用户的数量
        List<com.example.chamberlainserver.Entry.UserActionLog> logs = userActionLogMapper.getActionLogsByTimeRange(startTime, endTime);
        return (int) logs.stream().map(com.example.chamberlainserver.Entry.UserActionLog::getUserId).distinct().count();
    }
    
    /**
     * 获取指定时间段内的活跃用户数
     */
    private int getActiveUsers(LocalDateTime startTime, LocalDateTime endTime) {
        // 使用原生SQL查询指定时间段内不同用户的数量
        List<com.example.chamberlainserver.Entry.UserActionLog> logs = userActionLogMapper.getActionLogsByTimeRange(startTime, endTime);
        return (int) logs.stream().map(com.example.chamberlainserver.Entry.UserActionLog::getUserId).distinct().count();
    }
    
    /**
     * 获取用户角色分布
     */
    private List<DashboardDTO.UserActivity.RoleDistribution> getUserRoleDistribution() {
        List<com.example.chamberlainserver.Entry.User> allUsers = userMapper.getAllUsers();
        Map<String, Long> roleCountMap = new HashMap<>();
        
        // 统计每个用户的角色
        for (com.example.chamberlainserver.Entry.User user : allUsers) {
            List<Role> roles = userRoleService.getRolesByUserId(user.getId());
            if (roles != null && !roles.isEmpty()) {
                // 如果用户有多个角色，每个角色都计数
                for (Role role : roles) {
                    String roleCode = role.getRoleCode();
                    roleCountMap.put(roleCode, roleCountMap.getOrDefault(roleCode, 0L) + 1);
                }
            } else {
                // 如果用户没有角色，计入默认角色
                roleCountMap.put("STUDENT", roleCountMap.getOrDefault("STUDENT", 0L) + 1);
            }
        }
        
        List<DashboardDTO.UserActivity.RoleDistribution> roleDistribution = new ArrayList<>();
        roleCountMap.forEach((role, count) -> {
            roleDistribution.add(new DashboardDTO.UserActivity.RoleDistribution(role, count.intValue()));
        });
        
        return roleDistribution;
    }
    
    @Override
    public List<DashboardDTO.CategoryRatio> getCategoryRatio() {
        // 获取所有物资
        List<Material> materials = materialMapper.getAllMaterials();
        
        // 按分类ID分组并计数
        Map<Integer, Long> categoryCountMap = materials.stream()
                .collect(Collectors.groupingBy(Material::getCategoryId, Collectors.counting()));
        
        // 计算总数
        int total = materials.size();
        
        // 构建结果列表
        List<DashboardDTO.CategoryRatio> result = new ArrayList<>();
        
        categoryCountMap.forEach((categoryId, count) -> {
            // 获取分类名称
            String categoryName = categoryMapper.getCategoryById(categoryId).getName();
            
            // 计算百分比
            int percentage = (int) (count * 100 / total);
            
            result.add(DashboardDTO.CategoryRatio.builder()
                    .categoryName(categoryName)
                    .count(count.intValue())
                    .percentage(percentage)
                    .build());
        });
        
        // 按数量降序排序
        result.sort((a, b) -> b.getCount() - a.getCount());
        
        return result;
    }
    

    
    @Override
    public List<DashboardDTO.MaterialUsage> getMaterialUsageRanking(DashboardQuery query) {
        // 根据物资出库记录统计使用频率
        List<DashboardDTO.MaterialUsage> result = new ArrayList<>();
        
        try {
            // 计算时间范围
            LocalDateTime endTime = LocalDateTime.now();
            LocalDateTime startTime;
            
            String period = query.getPeriod() != null ? query.getPeriod() : "month";
            switch (period.toLowerCase()) {
                case "day":
                    startTime = endTime.minusDays(1);
                    break;
                case "week":
                    startTime = endTime.minusDays(7);
                    break;
                case "month":
                    startTime = endTime.minusMonths(1);
                    break;
                case "year":
                    startTime = endTime.minusYears(1);
                    break;
                default:
                    startTime = endTime.minusMonths(1);
            }
            
            // 查询指定时间范围内的出库记录，统计物资使用频率
            List<MaterialStockLog> stockLogs = materialStockLogMapper.getStockLogsByTimeRange(startTime, endTime);
            
            // 按物资ID分组统计出库次数
            Map<Long, Integer> materialUsageMap = new HashMap<>();
            Map<Long, String> materialNameMap = new HashMap<>();
            
            for (MaterialStockLog log : stockLogs) {
                // 只统计出库操作（changeQuantity < 0）
                if (log.getChangeQuantity() != null && log.getChangeQuantity() < 0) {
                    Long materialId = log.getMaterialId();
                    materialUsageMap.put(materialId, materialUsageMap.getOrDefault(materialId, 0) + 1);
                    materialNameMap.put(materialId, log.getMaterialName());
                }
            }
            
            // 转换为结果列表并按使用次数排序
            for (Map.Entry<Long, Integer> entry : materialUsageMap.entrySet()) {
                Long materialId = entry.getKey();
                Integer usageCount = entry.getValue();
                String materialName = materialNameMap.get(materialId);
                
                // 获取物资信息以获取分类名称
                Material material = materialMapper.getMaterialById(materialId);
                String categoryName = "未分类";
                if (material != null && material.getCategoryId() != null) {
                    var category = categoryMapper.getCategoryById(material.getCategoryId());
                    if (category != null) {
                        categoryName = category.getName();
                    }
                }
                
                result.add(DashboardDTO.MaterialUsage.builder()
                    .materialName(materialName)
                    .usageCount(usageCount)
                    .categoryName(categoryName)
                    .build());
            }
            
            // 按使用次数降序排序
            result.sort((a, b) -> b.getUsageCount().compareTo(a.getUsageCount()));
            
            // 根据limit参数限制返回数量
            int limit = query.getLimit() != null ? query.getLimit() : 10;
            return result.stream().limit(limit).collect(Collectors.toList());
            
        } catch (Exception e) {
            // 如果查询失败，返回模拟数据
            result.add(DashboardDTO.MaterialUsage.builder().materialName("A4纸").usageCount(120).categoryName("办公用品").build());
            result.add(DashboardDTO.MaterialUsage.builder().materialName("笔记本电脑").usageCount(80).categoryName("电子设备").build());
            result.add(DashboardDTO.MaterialUsage.builder().materialName("投影仪").usageCount(75).categoryName("教学器材").build());
            result.add(DashboardDTO.MaterialUsage.builder().materialName("白板笔").usageCount(60).categoryName("办公用品").build());
            result.add(DashboardDTO.MaterialUsage.builder().materialName("消毒液").usageCount(50).categoryName("清洁用品").build());
            
            // 按使用次数降序排序
            result.sort((a, b) -> b.getUsageCount() - a.getUsageCount());
            
            // 限制返回数量
            return result.stream().limit(query.getLimit()).collect(Collectors.toList());
        }
    }
    
    @Override
    public List<DashboardDTO.LowStockMaterial> getLowStockMaterials(Integer limit) {
        // 获取所有物资
        List<Material> materials = materialMapper.getAllMaterials();
        
        // 筛选库存低于最低库存的物资
        List<Material> lowStockMaterials = materials.stream()
                .filter(m -> m.getQuantity() < m.getMinQuantity())
                .collect(Collectors.toList());
        
        // 构建结果列表
        List<DashboardDTO.LowStockMaterial> result = new ArrayList<>();
        
        for (Material material : lowStockMaterials) {
            // 获取分类名称
            String categoryName = categoryMapper.getCategoryById(material.getCategoryId()).getName();
            
            // 计算缺少数量
            int shortage = material.getMinQuantity() - material.getQuantity();
            
            result.add(DashboardDTO.LowStockMaterial.builder()
                    .id(material.getId())
                    .materialName(material.getMaterialName())
                    .categoryName(categoryName)
                    .quantity(material.getQuantity())
                    .minQuantity(material.getMinQuantity())
                    .unit(material.getUnit())
                    .shortage(shortage)
                    .build());
        }
        
        // 按缺少数量降序排序
        result.sort((a, b) -> b.getShortage() - a.getShortage());
        
        // 限制返回数量
        return result.stream().limit(limit).collect(Collectors.toList());
    }
    
    @Override
    public DashboardDTO.TrippingStats getTrippingStats(String period) {
        // 获取当前时间
        LocalDateTime now = LocalDateTime.now();
        
        // 根据统计周期确定起始时间
        LocalDateTime startTime;
        switch (period) {
            case "week":
                startTime = now.minusDays(7);
                break;
            case "month":
                startTime = now.minusMonths(1);
                break;
            case "quarter":
                startTime = now.minusMonths(3);
                break;
            case "year":
                startTime = now.minusYears(1);
                break;
            default:
                startTime = now.minusMonths(1);
                break;
        }
        
        // 获取所有跳闸记录
        List<DormTrippingRecord> allRecords = trippingRecordMapper.getAllRecords();
        
        // 筛选指定时间段内的记录
        List<DormTrippingRecord> periodRecords = allRecords.stream()
                .filter(r -> r.getTrippingTime().isAfter(startTime))
                .collect(Collectors.toList());
        
        // 统计总记录数
        int totalCount = periodRecords.size();
        
        // 统计已处理和待处理记录数
        int handledCount = 0;
        int pendingCount = 0;
        
        // 计算平均功率和最大功率
        BigDecimal totalPower = BigDecimal.ZERO;
        BigDecimal maxPower = BigDecimal.ZERO;
        
        // 统计时间段分布
        Map<String, Integer> timeDistribution = new HashMap<>();
        timeDistribution.put("morning", 0);   // 6:00-12:00
        timeDistribution.put("afternoon", 0); // 12:00-18:00
        timeDistribution.put("evening", 0);   // 18:00-24:00
        timeDistribution.put("night", 0);     // 0:00-6:00
        
        for (DormTrippingRecord record : periodRecords) {
            // 统计处理状态
            if (record.getIsHandled() == true) {
                handledCount++;
            } else {
                pendingCount++;
            }
            
            // 累计功率
            totalPower = totalPower.add(record.getTrippingPower());
            
            // 更新最大功率
            if (record.getTrippingPower().compareTo(maxPower) > 0) {
                maxPower = record.getTrippingPower();
            }
            
            // 统计时间段分布
            int hour = record.getTrippingTime().getHour();
            if (hour >= 6 && hour < 12) {
                timeDistribution.put("morning", timeDistribution.getOrDefault("morning", 0) + 1);
            } else if (hour >= 12 && hour < 18) {
                timeDistribution.put("afternoon", timeDistribution.getOrDefault("afternoon", 0) + 1);
            } else if (hour >= 18 && hour < 24) {
                timeDistribution.put("evening", timeDistribution.getOrDefault("evening", 0) + 1);
            } else {
                timeDistribution.put("night", timeDistribution.getOrDefault("night", 0) + 1);
            }
        }
        
        // 计算平均功率
        BigDecimal averagePower = totalCount > 0 ?
                totalPower.divide(new BigDecimal(totalCount), 2, RoundingMode.HALF_UP) :
                BigDecimal.ZERO;
        
        return DashboardDTO.TrippingStats.builder()
                .totalCount(totalCount)
                .handledCount(handledCount)
                .pendingCount(pendingCount)
                .averagePower(averagePower)
                .maxPower(maxPower)
                .timeDistribution(timeDistribution)
                .build();
    }
    
    @Override
    public List<DashboardDTO.PowerDistribution> getPowerDistribution() {
        // 获取所有跳闸记录
        List<DormTrippingRecord> records = trippingRecordMapper.getAllRecords();
        
        // 定义功率范围（单位：瓦特）
        Map<String, Integer> powerRanges = new LinkedHashMap<>();
        powerRanges.put("0-1000W", 0);
        powerRanges.put("1000-2000W", 0);
        powerRanges.put("2000-3000W", 0);
        powerRanges.put("3000-4000W", 0);
        powerRanges.put("4000W以上", 0);
        
        // 统计各功率范围的记录数
        for (DormTrippingRecord record : records) {
            BigDecimal power = record.getTrippingPower(); // 数据库中的功率单位为瓦特
            
            if (power.compareTo(new BigDecimal(1000)) < 0) {
                powerRanges.put("0-1000W", powerRanges.getOrDefault("0-1000W", 0) + 1);
            } else if (power.compareTo(new BigDecimal(2000)) < 0) {
                powerRanges.put("1000-2000W", powerRanges.getOrDefault("1000-2000W", 0) + 1);
            } else if (power.compareTo(new BigDecimal(3000)) < 0) {
                powerRanges.put("2000-3000W", powerRanges.getOrDefault("2000-3000W", 0) + 1);
            } else if (power.compareTo(new BigDecimal(4000)) < 0) {
                powerRanges.put("3000-4000W", powerRanges.getOrDefault("3000-4000W", 0) + 1);
            } else {
                powerRanges.put("4000W以上", powerRanges.getOrDefault("4000W以上", 0) + 1);
            }
        }
        
        // 构建结果列表
        List<DashboardDTO.PowerDistribution> result = new ArrayList<>();
        
        powerRanges.forEach((range, count) -> {
            result.add(DashboardDTO.PowerDistribution.builder()
                    .range(range)
                    .count(count)
                    .build());
        });
        
        return result;
    }
    
    @Override
    public DashboardDTO.TimeDistribution getTimeDistribution(DashboardQuery query) {
        // 获取当前时间
        LocalDateTime now = LocalDateTime.now();
        
        // 根据统计周期确定起始时间
        LocalDateTime startTime;
        switch (query.getPeriod()) {
            case "week":
                startTime = now.minusDays(7);
                break;
            case "month":
                startTime = now.minusMonths(1);
                break;
            case "quarter":
                startTime = now.minusMonths(3);
                break;
            case "year":
                startTime = now.minusYears(1);
                break;
            default:
                startTime = now.minusMonths(1);
                break;
        }
        
        // 获取所有跳闸记录
        List<DormTrippingRecord> allRecords = trippingRecordMapper.getAllRecords();
        
        // 筛选指定时间段内的记录
        List<DormTrippingRecord> periodRecords = allRecords.stream()
                .filter(r -> r.getTrippingTime().isAfter(startTime))
                .collect(Collectors.toList());
        
        // 根据分布类型统计
        List<DashboardDTO.TimeDistribution.DistributionItem> distribution = new ArrayList<>();
        
        switch (query.getType()) {
            case "hourly":
                // 按小时统计
                Map<Integer, Integer> hourlyDistribution = new HashMap<>();
                for (int i = 0; i < 24; i++) {
                    hourlyDistribution.put(i, 0);
                }
                
                for (DormTrippingRecord record : periodRecords) {
                    int hour = record.getTrippingTime().getHour();
                    hourlyDistribution.put(hour, hourlyDistribution.getOrDefault(hour, 0) + 1);
                }
                
                for (int i = 0; i < 24; i++) {
                    String timePoint = String.format("%02d:00", i);
                    distribution.add(DashboardDTO.TimeDistribution.DistributionItem.builder()
                            .timePoint(timePoint)
                            .count(hourlyDistribution.get(i))
                            .build());
                }
                break;
                
            case "daily":
                // 按日统计
                Map<LocalDate, Integer> dailyDistribution = new HashMap<>();
                LocalDate startDate = startTime.toLocalDate();
                LocalDate endDate = now.toLocalDate();
                
                for (LocalDate date = startDate; !date.isAfter(endDate); date = date.plusDays(1)) {
                    dailyDistribution.put(date, 0);
                }
                
                for (DormTrippingRecord record : periodRecords) {
                    LocalDate date = record.getTrippingTime().toLocalDate();
                    dailyDistribution.put(date, dailyDistribution.getOrDefault(date, 0) + 1);
                }
                
                DateTimeFormatter dailyFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
                for (LocalDate date = startDate; !date.isAfter(endDate); date = date.plusDays(1)) {
                    distribution.add(DashboardDTO.TimeDistribution.DistributionItem.builder()
                            .timePoint(date.format(dailyFormatter))
                            .count(dailyDistribution.get(date))
                            .build());
                }
                break;
                
            case "weekly":
                // 按周统计
                Map<String, Integer> weeklyDistribution = new LinkedHashMap<>();
                weeklyDistribution.put("周一", 0);
                weeklyDistribution.put("周二", 0);
                weeklyDistribution.put("周三", 0);
                weeklyDistribution.put("周四", 0);
                weeklyDistribution.put("周五", 0);
                weeklyDistribution.put("周六", 0);
                weeklyDistribution.put("周日", 0);
                
                for (DormTrippingRecord record : periodRecords) {
                    int dayOfWeek = record.getTrippingTime().getDayOfWeek().getValue();
                    String day = "";
                    switch (dayOfWeek) {
                        case 1: day = "周一"; break;
                        case 2: day = "周二"; break;
                        case 3: day = "周三"; break;
                        case 4: day = "周四"; break;
                        case 5: day = "周五"; break;
                        case 6: day = "周六"; break;
                        case 7: day = "周日"; break;
                    }
                    weeklyDistribution.put(day, weeklyDistribution.getOrDefault(day, 0) + 1);
                }
                
                weeklyDistribution.forEach((day, count) -> {
                    distribution.add(DashboardDTO.TimeDistribution.DistributionItem.builder()
                            .timePoint(day)
                            .count(count)
                            .build());
                });
                break;
                
            case "monthly":
                // 按月统计
                Map<String, Integer> monthlyDistribution = new LinkedHashMap<>();
                for (int i = 1; i <= 12; i++) {
                    monthlyDistribution.put(String.valueOf(i) + "月", 0);
                }
                
                for (DormTrippingRecord record : periodRecords) {
                    int month = record.getTrippingTime().getMonthValue();
                    String monthStr = String.valueOf(month) + "月";
                    monthlyDistribution.put(monthStr, monthlyDistribution.getOrDefault(monthStr, 0) + 1);
                }
                
                monthlyDistribution.forEach((month, count) -> {
                    distribution.add(DashboardDTO.TimeDistribution.DistributionItem.builder()
                            .timePoint(month)
                            .count(count)
                            .build());
                });
                break;
        }
        
        return DashboardDTO.TimeDistribution.builder()
                .type(query.getType())
                .distribution(distribution)
                .build();
    }
    
    @Override
    public List<DashboardDTO.ClassRanking> getClassRanking(DashboardQuery query) {
        // 获取当前时间
        LocalDateTime now = LocalDateTime.now();
        
        // 根据统计周期确定起始时间
        LocalDateTime startTime;
        switch (query.getPeriod()) {
            case "week":
                startTime = now.minusDays(7);
                break;
            case "month":
                startTime = now.minusMonths(1);
                break;
            case "quarter":
                startTime = now.minusMonths(3);
                break;
            case "year":
                startTime = now.minusYears(1);
                break;
            default:
                startTime = now.minusMonths(1);
                break;
        }
        
        // 获取所有跳闸记录
        List<DormTrippingRecord> allRecords = trippingRecordMapper.getAllRecords();
        
        // 筛选指定时间段内的记录
        List<DormTrippingRecord> periodRecords = allRecords.stream()
                .filter(r -> r.getTrippingTime().isAfter(startTime))
                .collect(Collectors.toList());
        
        // 按班级分组并计数
        Map<String, Map<String, Integer>> classCountMap = new HashMap<>();
        
        for (DormTrippingRecord record : periodRecords) {
            String className = record.getClassName();
            String counselor = record.getCounselor();
            
            if (!classCountMap.containsKey(className)) {
                classCountMap.put(className, new HashMap<>());
                classCountMap.get(className).put("count", 0);
                classCountMap.get(className).put("counselor", 0);
            }
            
            Map<String, Integer> classData = classCountMap.get(className);
            classData.put("count", classData.getOrDefault("count", 0) + 1);
            classCountMap.get(className).put("counselor", counselor.hashCode());
        }
        
        // 构建结果列表
        List<DashboardDTO.ClassRanking> result = new ArrayList<>();
        
        classCountMap.forEach((className, data) -> {
            // 获取辅导员姓名
            String counselor = periodRecords.stream()
                    .filter(r -> r.getClassName().equals(className))
                    .findFirst()
                    .map(DormTrippingRecord::getCounselor)
                    .orElse("");
            
            result.add(DashboardDTO.ClassRanking.builder()
                    .className(className)
                    .count(data.get("count"))
                    .counselor(counselor)
                    .build());
        });
        
        // 按跳闸次数降序排序
        result.sort((a, b) -> b.getCount() - a.getCount());
        
        // 限制返回数量
        return result.stream().limit(query.getLimit()).collect(Collectors.toList());
    }
    
    @Override
    public DashboardDTO.LoginStats getLoginStats(String period) {
        // 获取当前时间
        LocalDateTime now = LocalDateTime.now();
        
        // 根据统计周期确定起始时间
        LocalDateTime startTime;
        switch (period) {
            case "week":
                startTime = now.minusDays(7);
                break;
            case "month":
                startTime = now.minusMonths(1);
                break;
            case "quarter":
                startTime = now.minusMonths(3);
                break;
            case "year":
                startTime = now.minusYears(1);
                break;
            default:
                startTime = now.minusMonths(1);
                break;
        }
        LocalDateTime endTime = now;
        
        // 从用户日志服务获取登录统计数据
        Map<String, Object> loginStats = userLogService.getLoginStats(startTime, endTime);
        
        // 获取总登录次数和独立用户数
        int totalLogins = loginStats.get("totalLogins") != null ? 
                Integer.parseInt(loginStats.get("totalLogins").toString()) : 0;
        int uniqueUsers = loginStats.get("uniqueUsers") != null ? 
                Integer.parseInt(loginStats.get("uniqueUsers").toString()) : 0;
        
        // 计算平均每用户登录次数
        double averageLoginsPerUser = uniqueUsers > 0 ? (double) totalLogins / uniqueUsers : 0;
        // 保留一位小数
        averageLoginsPerUser = Math.round(averageLoginsPerUser * 10) / 10.0;
        
        // 获取每日登录统计数据
        List<Map<String, Object>> dailyStats = userLogService.getDailyLoginCounts(startTime, endTime);
        
        // 转换为前端所需的时间分布数据格式
        List<DashboardDTO.LoginStats.TimeCount> timeDistribution = new ArrayList<>();
        
        for (Map<String, Object> stat : dailyStats) {
            String date = stat.get("date").toString();
            int count = Integer.parseInt(stat.get("count").toString());
            
            timeDistribution.add(DashboardDTO.LoginStats.TimeCount.builder()
                    .date(date)
                    .count(count)
                    .build());
        }
        
        return DashboardDTO.LoginStats.builder()
                .totalLogins(totalLogins)
                .uniqueUsers(uniqueUsers)
                .averageLoginsPerUser(averageLoginsPerUser)
                .timeDistribution(timeDistribution)
                .build();
    }
    
    @Override
    public List<DashboardDTO.OperationDistribution> getOperationDistribution(String period) {
        // 获取当前时间
        LocalDateTime now = LocalDateTime.now();
        
        // 根据统计周期确定起始时间
        LocalDateTime startTime;
        switch (period) {
            case "week":
                startTime = now.minusDays(7);
                break;
            case "month":
                startTime = now.minusMonths(1);
                break;
            case "quarter":
                startTime = now.minusMonths(3);
                break;
            case "year":
                startTime = now.minusYears(1);
                break;
            default:
                startTime = now.minusMonths(1);
                break;
        }
        LocalDateTime endTime = now;
        
        // 从用户日志服务获取操作分布数据
        List<Map<String, Object>> operationTypeStats = userLogService.getOperationDistribution(startTime, endTime);
        
        // 计算总操作数
        int totalOperations = operationTypeStats.stream()
                .mapToInt(stat -> ((Number) stat.get("count")).intValue())
                .sum();
        
        // 转换为前端所需的操作分布数据格式
        List<DashboardDTO.OperationDistribution> result = new ArrayList<>();
        
        for (Map<String, Object> stat : operationTypeStats) {
            String operation = stat.get("operation").toString();
            int count = ((Number) stat.get("count")).intValue();
            // 计算百分比并四舍五入
            int percentage = totalOperations > 0 ? Math.round((float) count * 100 / totalOperations) : 0;
            
            result.add(DashboardDTO.OperationDistribution.builder()
                    .operation(operation)
                    .count(count)
                    .percentage(percentage)
                    .build());
        }
        
        return result;
    }
    
    @Override
    public DashboardDTO.MaterialStockTrend getMaterialStockTrend(String period, Integer days) {
        // 设置默认天数
        if (days == null || days <= 0) {
            days = 30;
        }
        
        // 计算时间范围
        LocalDate endDate = LocalDate.now();
        LocalDate startDate = endDate.minusDays(days);
        
        List<Map<String, Object>> trendData;
        
        // 根据统计周期获取不同粒度的数据
        switch (period.toLowerCase()) {
            case "daily":
                trendData = materialStockLogMapper.getDailyStockTrend(startDate, endDate);
                break;
            case "weekly":
                trendData = materialStockLogMapper.getWeeklyStockTrend(startDate, endDate);
                break;
            case "monthly":
                trendData = materialStockLogMapper.getMonthlyStockTrend(startDate, endDate);
                break;
            default:
                trendData = materialStockLogMapper.getDailyStockTrend(startDate, endDate);
                period = "daily";
                break;
        }
        
        // 转换数据格式并计算总库存
        List<DashboardDTO.StockTrendItem> trendItems = new ArrayList<>();
        int totalInbound = 0;
        int totalOutbound = 0;
        int totalChange = 0;
        
        // 获取起始日期的总库存作为基准
        Integer baseStock = materialStockLogMapper.getTotalInventoryByDate(startDate);
        if (baseStock == null) {
            baseStock = 0;
        }
        int currentTotalStock = baseStock;
        
        for (Map<String, Object> data : trendData) {
            String timePoint = getTimePointFromData(data, period);
            Integer inboundQuantity = getIntegerFromMap(data, "inbound_quantity");
            Integer outboundQuantity = getIntegerFromMap(data, "outbound_quantity");
            Integer netChange = getIntegerFromMap(data, "net_change");
            
            // 累计计算总库存
            currentTotalStock += netChange;
            
            DashboardDTO.StockTrendItem item = DashboardDTO.StockTrendItem.builder()
                    .timePoint(timePoint)
                    .totalStock(currentTotalStock)
                    .inboundQuantity(inboundQuantity)
                    .outboundQuantity(outboundQuantity)
                    .netChange(netChange)
                    .build();
            
            trendItems.add(item);
            
            totalInbound += inboundQuantity;
            totalOutbound += outboundQuantity;
            totalChange += netChange;
        }
        
        return DashboardDTO.MaterialStockTrend.builder()
                .trendData(trendItems)
                .period(period)
                .totalInbound(totalInbound)
                .totalOutbound(totalOutbound)
                .totalChange(totalChange)
                .build();
    }
    
    @Override
    public DashboardDTO.MaterialStockTrendDetail getMaterialStockTrendDetail(Long materialId, String period, Integer days) {
        // 设置默认天数
        if (days == null || days <= 0) {
            days = 30;
        }
        
        // 计算时间范围
        LocalDate endDate = LocalDate.now();
        LocalDate startDate = endDate.minusDays(days);
        
        // 获取物资信息
        Material material = materialMapper.getMaterialById(materialId);
        if (material == null) {
            throw new IllegalArgumentException("物资不存在");
        }
        
        // 获取物资分类信息
        String categoryName = "";
        if (material.getCategoryId() != null) {
            var category = categoryMapper.getCategoryById(material.getCategoryId());
            if (category != null) {
                categoryName = category.getName();
            }
        }
        
        // 获取物资库存趋势数据
        List<Map<String, Object>> trendData = materialStockLogMapper.getMaterialStockTrend(
                materialId, startDate, endDate, period.toLowerCase());
        
        // 转换数据格式
        List<DashboardDTO.StockTrendItem> trendItems = new ArrayList<>();
        
        // 获取起始库存
        List<Map<String, Object>> initialStock = materialStockLogMapper.getMaterialStockByDate(startDate);
        int currentStock = material.getQuantity(); // 当前库存作为基准
        
        // 如果有历史数据，从最早的记录开始计算
        if (!trendData.isEmpty()) {
            // 计算起始库存（当前库存减去所有变化量）
            int totalChange = trendData.stream()
                    .mapToInt(data -> getIntegerFromMap(data, "net_change"))
                    .sum();
            currentStock = material.getQuantity() - totalChange;
        }
        
        for (Map<String, Object> data : trendData) {
            String timePoint = getTimePointFromData(data, period);
            Integer inboundQuantity = getIntegerFromMap(data, "inbound_quantity");
            Integer outboundQuantity = getIntegerFromMap(data, "outbound_quantity");
            Integer netChange = getIntegerFromMap(data, "net_change");
            
            // 累计计算库存
            currentStock += netChange;
            
            DashboardDTO.StockTrendItem item = DashboardDTO.StockTrendItem.builder()
                    .timePoint(timePoint)
                    .totalStock(currentStock)
                    .inboundQuantity(inboundQuantity)
                    .outboundQuantity(outboundQuantity)
                    .netChange(netChange)
                    .build();
            
            trendItems.add(item);
        }
        
        return DashboardDTO.MaterialStockTrendDetail.builder()
                .materialId(materialId)
                .materialName(material.getMaterialName())
                .categoryName(categoryName)
                .trendData(trendItems)
                .currentStock(material.getQuantity())
                .minStock(material.getMinQuantity())
                .status(material.getStatus())
                .build();
    }
    
    /**
     * 从数据Map中提取时间点字符串
     */
    private String getTimePointFromData(Map<String, Object> data, String period) {
        switch (period.toLowerCase()) {
            case "daily":
                return data.get("date") != null ? data.get("date").toString() : "";
            case "weekly":
                return data.get("week") != null ? data.get("week").toString() : "";
            case "monthly":
                return data.get("month") != null ? data.get("month").toString() : "";
            default:
                return data.get("time_point") != null ? data.get("time_point").toString() : "";
        }
    }
    
    /**
     * 从Map中安全获取Integer值
     */
    private Integer getIntegerFromMap(Map<String, Object> map, String key) {
        Object value = map.get(key);
        if (value == null) {
            return 0;
        }
        if (value instanceof Number) {
            return ((Number) value).intValue();
        }
        try {
            return Integer.parseInt(value.toString());
        } catch (NumberFormatException e) {
            return 0;
        }
    }
}